<?php
require_once("Formulario.php");

function __DEBUG__($objeto = false) {
	if (!$objeto) return;
	if (is_array($objeto) || is_object($objeto)) {
		echo "<pre>";
		print_r($objeto);
		echo "</pre>";
		return;
	}
	echo "<pre>";
	echo $objeto;
	echo "</pre>";
}

abstract class TemplateAsForm extends SpecialPage {

	/**
		VARIABLES PERSONALIZABLES:
		- $nombrePlantilla: indica el nombre de la plantilla que utilizara al crear el articulo. Al final crea el articulo como 
		  {{$nombrePlantilla ... }}
		- $nombrePaginaEspecial: indica el nombre con el que aparece la pagina especial en la lista de paginas especiales
		- $categorias: es un array asociativo del tipo array( "id-categoria-1" => "descripcion categoria 1", ... ) que indica las posibles
		  categorias en que puede ser añadido el articulo
		- $numeroPosiblesCategorias: indica cuantas posibles categorias se pueden elegir
		- $numeroCategoriasRequeridas: indica cuantas categorias distintas se deben haber seleccionado
		- $maxIntentos: indica cuantas veces se va a reintentar (como maximo) obtener un nombre para el articulo, mediante llamadas a la funcion
		  "generarNombreArticulo"

		FUNCIONES A SOBREESCRIBIR (obligatoriamente)
		- protected function &crearObjetoFormulario()
			devuelve un objeto de tipo Formulario, que es el que tiene añadidos los campos que se mostraran y cuyos identificadores
			se utilizaran como LHS de los valores de la plantilla

		- protected function generarNombreArticulo(&$objeto, $intento, $reintentosRestantes);
			funcion que devuelve un String con un posible nombre de articulo. 
				* $objeto es un objeto cuyos atributos se corresponden con los distintos campos del formulario, ya procesados, derivados 
				  (si procede) y validados
				* $intento indica cuantas veces se ha intentado obtener previamente un nombre para el articulo (si existe, se reintentara)
				* $reintentosRestantes indica cuantas veces (como maximo) se llamara a esta funcion para buscar alternativas, en caso de
				  que ya exista un articulo con el nombre devuelto

		CALLBACKS
		- function antesDeCrear(&$objeto)
			funcion que se llama justo antes de crear el articulo. Se puede utilizar para modificar los valores, añadir o eliminar propiedades, etc. En realidad el articulo
			se va a generar sera a partir de las propiedades de este objeto. Si el objeto tiene $objeto->p1, $objeto->p2, $objeto->p3, se creara el articulo como {{plantilla |
			p1 = valorp1 | p2 = valorp2 | p3 = valorp3 }}. De modo que si se quieren incluir valores derivados, este es buen momento (a parte de los mismos valores derivados).

			** El valor de retorno de esta funcion se interpreta como "motivo de cancelacion de la creacion". De modo que si se devuelve un valor null (o false), se crea el articulo
			con las modificaciones que se hayan hecho. En caso de que por algun motivo no se pueda crear (hay algun formato no valido, se ha hecho una comprobacion que no se cumple, etc.),
			se deberia devolver una cadena de texto que explicase el motivo de cancelacion, que se mostrara junto con el formulario.

		- function generaHTMLCabecera()
			funcion que devuelve un string con codigo HTML que se pondra en la pagina especial, antes del formulario.

		- function generaHTMLPie()
			funcion equivalente a la anterior, que se llama despues del boton

		*************
		
		Lo normal es que la clase que descienda de esta tenga la siguiente forma

		class CLASE extends FormAsTemplate {
			var $nombrePlantilla = "MI_PLANTILLA";
			var $nombrePaginaEspecial = "CREAR MI PLANTILLA";
			
			protected function &crearObjetoFormulario(){
				$form = new Formulario();
				$form->CreaInput(...);
				...
				return $form;
			}

			protected function generarNombreArticulo(&$objeto, $intento, $reintentosRestantes) {
				return "NOMBRE_ARTICULO-{$intento}";
			}
		}

		***************

		TODO:
			- Incorporar funcion para ** editar ** un articulo mediante el formulario (via parametro)
			- Incorporar algun CALLBACK mas
	*/
	var $nombrePlantilla = 'SET YOUR OWN TEMPLATE NAME IN $nombrePlantilla';
	var $nombrePaginaEspecial = 'SET YOUR OWN TEMPLATE NAME IN $nombrePaginaEspecial';
	var $categorias = null;
	var $numeroPosiblesCategorias = 0;
	var $numeroCategoriasRequeridas = 0;
	var $categoriasForzadas = array();
	var $CALENDAR_SUPPORT = true;
	var $CALENDAR_PATH = "/js/jscalendar-1.0";
	var $maxIntentos = 10;

	abstract protected function &crearObjetoFormulario();
	abstract protected function generarNombreArticulo(&$objeto, $intento, $reintentosRestantes);

	function antesDeCrear(&$objeto) { return null; }
	function generaHTMLCabecera() {	return ""; }
	function generaHTMLPie() {	return ""; }

	/** IMPLEMENTACION GENERICA 
		Esta parte ya no se puede personalizar.
	*/
	var $objetoFormulario = null;

	function __construct() {
		parent::__construct( get_class($this) );

		global $wgMessageCache;
		$wgMessageCache->addMessages( array(
	                strtolower(get_class($this)) => $this->nombrePaginaEspecial
	        ) );
		$wgMessageCache->loadMessagesFile(dirname(__file__)."/TemplateAsForm.i18n.php");
	}
 
	function execute( $par ) {

		global $wgRequest, $wgOut;

		$this->objetoFormulario = $this->crearObjetoFormulario();

		/** Primero miramos a ver si se ha establecido el objeto de formulario */
		if (!$this->objetoFormulario) {
			$wgOut->addHTML("<h1>".wfMsg('no-form')."</h1>");
			$this->setHeaders();
			return;			
		}

		$valores_categorias = $this->categoriasForzadas;
		$necesitaMostrarFormulario = true;

		$creando = $wgRequest->getVal('__creation__')=='true';
		if ($creando) {
			$necesitaMostrarFormulario = false;

			// Vamos a recuperar las categorias
			for ($i=0; $i<min($this->numeroPosiblesCategorias, count($this->categorias)); $i++) {
				$cat_name = "__categoria__{$i}";
				if (array_key_exists($cat_name,$_POST)) {
					$cat_val = $_POST[$cat_name];
					if ($cat_val!='') {
						if (!array_key_exists($cat_val,$this->categorias)) {
							// Nos la estan intentando colar... posible tampering
							trigger_error(wfMsg('cat-value',$cat_val, $cat_name), E_USER_WARNING);
						} else {
							if (!in_array($cat_val,$valores_categorias))
								array_push($valores_categorias, $cat_val);
						}
					}
				}
			}

			/** Ahora preparamos la cadena de las categorias */
			global $wgContLang;
			$ns = $wgContLang->getFormattedNsText(NS_CATEGORY);
			$categories_string = "";
			foreach ($valores_categorias as $cur_categoria)
				$categories_string = "{$categories_string}[[{$ns}:{$cur_categoria}]] ";

			/** No se si es mas correcto lo de arriba o lo de abajo. En realidad, es correcta la de POST, ya que enviamos el formulario con POST y data = POST+GET. El problema podria
				venir por futuras versiones */
			// $this->objetoFormulario->recuperaValores($wgRequest->data);
			$this->objetoFormulario->recuperaValores($_POST);
			$validacion = $this->objetoFormulario->validaFormulario();

			if ((count($validacion->vacios)>0) || (count($validacion->vacios)>0) || (count($valores_categorias)<$this->numeroCategoriasRequeridas)) {
				$wgOut->addHTML("<div id='errores-form'><h1>".wfMsg('error-form')."</h1>");
			}
			if (count($validacion->vacios)>0) {
				$wgOut->addHTML("<h2>".wfMsg('objetos-requeridos')."</h2>");
				$wgOut->addHTML("<ul>");
				foreach ($validacion->vacios as $campo) {
					$wgOut->addHTML("<li>".$this->objetoFormulario->elementos[$campo]->label."</li>");
				}
				$wgOut->addHTML("</ul>");
				$necesitaMostrarFormulario = true;
			}
			if (count($validacion->invalidos)>0) {
				$wgOut->addHTML("<h2>".wfMsg('formato-invalido')."</h2>");
				$wgOut->addHTML("<ul>");
				foreach ($validacion->invalidos as $campo) {
					$wgOut->addHTML("<li>".$this->objetoFormulario->elementos[$campo]->label."</li>");
				}
				$wgOut->addHTML("</ul>");
				$necesitaMostrarFormulario = true;
			}
			if (count($valores_categorias)<$this->numeroCategoriasRequeridas) {
				$wgOut->addHTML("<h2>".wfMsg('min-categories',$this->numeroCategoriasRequeridas)."</h2>");
				$necesitaMostrarFormulario = true;
			}
			if ((count($validacion->vacios)>0) || (count($validacion->vacios)>0) || (count($valores_categorias)<$this->numeroCategoriasRequeridas)) {
				$wgOut->addHTML("</div>");
			}
			if (!$necesitaMostrarFormulario) {
				$objeto = $this->objetoFormulario->construyeObjeto();
				if ($objeto==null) {
					$necesitaMostrarFormulario = true;
				} else {
					$motivoCancelacion = $this->antesDeCrear($objeto);

					if (!$motivoCancelacion) {
						$contenidoTxt = '{{'.$this->nombrePlantilla."\n";
						foreach ($objeto as $key => $valor) {
							$contenidoTxt = "{$contenidoTxt}| {$key} = {$valor}\n";
						}
						$contenidoTxt = $contenidoTxt."}}";

						// Ahora buscamos un nombre
						$intento = 0;
						do {
							$intento++;
							$nombreArticulo = $this->generarNombreArticulo($objeto, $intento, $this->maxIntentos - $intento);
							$artTitle = Title::newFromText($nombreArticulo);
							$articulo = MediaWiki::articleFromTitle( $artTitle );	
						} while (($articulo->getID()!=0)&&($intento<$this->maxIntentos));

						if ($articulo->getID()!=0) {
							// El articulo no ha podido ser creado
							$wgOut->addHTML("<h1>".wfMsg('no-proper-name')."</h1>");
							$necesitaMostrarFormulario = true;
						} else {
							/** Finalmente le ponemos las categorias */
							$contenidoTxt = "{$contenidoTxt}\n{$categories_string}";

							/** Ahora ya creamos el articulo */
							$nuevoArticulo = new Article($artTitle);
							$nuevoArticulo->doEdit($contenidoTxt,"",EDIT_NEW);
							$wgOut->redirect($artTitle->getFullURL(''));
/*
							__DEBUG__($contenidoTxt);
*/
						}
					} else {
						$wgOut->addHTML("<h1>".wfMsg('article-creation-cancelled')."</h1>");
						if (!is_string($motivoCancelacion)) {
							$wgOut->addHTML("<h2>".wfMsg('no-messages')."</h2>");
						} else {
							$wgOut->addHTML("<h2>{$motivoCancelacion}</h2>");
						}
						$necesitaMostrarFormulario = true;
					}
				}
			}
		}

		if ($necesitaMostrarFormulario) {
			$this->crearFormularioHTML($this->objetoFormulario, $valores_categorias);
		} 
 
		$this->setHeaders();
 	}

	function crearFormularioHTML(&$form, $valores_categorias) {
		global $wgOut;

		if ($this->CALENDAR_SUPPORT) {
			$wgOut->addScript("<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"{$this->CALENDAR_PATH}/calendar-win2k-cold-1.css\" title=\"win2k-cold-1\" />");
			$wgOut->addScript("<script type=\"text/javascript\" src=\"{$this->CALENDAR_PATH}/calendar.js\"></script>\n");
			$wgOut->addScript("<script type=\"text/javascript\" src=\"{$this->CALENDAR_PATH}/lang/calendar-es.js\"></script>\n");
			$wgOut->addScript("<script type=\"text/javascript\" src=\"{$this->CALENDAR_PATH}/calendar-setup.js\"></script>\n");
		}

		$wgOut->addHTML($this->generaHTMLCabecera());

		$wgOut->addHTML( Xml::openElement( 'form', array(
                                'method' => 'post',
                                'action' => SpecialPage::getTitleFor( get_class($this) )->escapeLocalUrl() ) ));
		$wgOut->addHTML( Xml::fieldset($this->nombrePaginaEspecial));

		$form->CALENDAR_SUPPORT = $this->CALENDAR_SUPPORT;
		$wgOut->addHTML( $form->generaCamposHTML() );
		$wgOut->addHTML( Xml::closeElement('fieldset'));

		if (($this->numeroPosiblesCategorias > 0) && (count($this->categorias)>0)) {
			$wgOut->addHTML( Xml::fieldset(wfMsg('categories-fs')));

			$cadena = "<ul>";
			for ($i=0; $i<min($this->numeroPosiblesCategorias, count($this->categorias)); $i++) {
				$cadena = $cadena . "<li><select id=\"__categoria__{$i}\" name=\"__categoria__{$i}\">";
				$cadena = $cadena . Xml::option(wfMsg('no-category'), "", false);
				$valor = array_shift($valores_categorias);
				foreach($this->categorias as $id => $nombre) {
					$cadena = $cadena . Xml::option($nombre, $id, ($id==$valor));
				}
				$cadena = $cadena . "</select></li>";
			}
			$cadena = "{$cadena}</ul>";

			$wgOut->addHTML($cadena);

			$wgOut->addHTML( Xml::closeElement('fieldset'));
		}

		$wgOut->addHTML (Xml::hidden( '__creation__','true').
                        Xml::closeElement( 'fieldset' ) .
                        Xml::submitButton( 'Crear' ) .
                        Xml::closeElement( 'form' )
		);

		$wgOut->addHTML($this->generaHTMLPie());
	}

}
